{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from binance.spot import Spot\n",
    "import time\n",
    "from datetime import datetime\n",
    "import pytz\n",
    "\n",
    "symbol = \"BTCUSDT\"\n",
    "# symbol = \"ETHUSDT\"\n",
    "\n",
    "\n",
    "def format_time(timestamp):\n",
    "    tz = pytz.timezone(\"Asia/Shanghai\")\n",
    "    return datetime.fromtimestamp(timestamp, tz).strftime(\"%Y-%m-%d %H:%M:%S\")\n",
    "\n",
    "\n",
    "def convert_to_beijing_time(ts):\n",
    "    tz = pytz.timezone(\"Asia/Shanghai\")\n",
    "    return datetime.fromtimestamp(ts // 1e3, tz)\n",
    "\n",
    "\n",
    "def get_data(symbol=symbol, interval=\"5m\", limit=\"500\"):\n",
    "    # 1. 获取K线原始数据\n",
    "    # client = Spot(base_url=\"https://data-api.binance.vision\")\n",
    "    client = Spot(base_url=\"https://data-api.binance.vision\")\n",
    "    # interval 1s, 1m, 5m, 1h, 1d,\n",
    "    # 1125-1216 1732475182000-1734289582000 震荡\n",
    "    # 1106-1125 1730833582000-1732475182000 上涨\n",
    "    # 0124 1737659180000\n",
    "    klines = client.klines(\n",
    "        symbol=symbol,\n",
    "        interval=interval,\n",
    "        limit=limit,\n",
    "        # startTime=\"1741276800000\",  # 2025-03-07 00:00:00+08:00\n",
    "        # startTime=\"1730833582000\",\n",
    "        # startTime=\"1737659180000\",\n",
    "        # startTime=\"1730833582000\",\n",
    "        # startTime=\"1732475182000\",\n",
    "        # endTime=\"1734289582000\",\n",
    "    )  # 示例：BTC/USDT 1小时K线\n",
    "\n",
    "    # 2. 转换为结构化数据\n",
    "    df = pd.DataFrame(\n",
    "        klines,\n",
    "        columns=[\n",
    "            \"Open Time\",\n",
    "            \"Open\",\n",
    "            \"High\",\n",
    "            \"Low\",\n",
    "            \"Close\",\n",
    "            \"Volume\",\n",
    "            \"Close Time\",\n",
    "            \"Quote Asset Volume\",\n",
    "            \"Number of Trades\",\n",
    "            \"Taker Buy Base\",\n",
    "            \"Taker Buy Quote\",\n",
    "            \"Ignore\",\n",
    "        ],\n",
    "    )\n",
    "\n",
    "    df[\"Time\"] = df[\"Open Time\"].apply(convert_to_beijing_time)\n",
    "\n",
    "    # # 4. 构建OHLC数据框架\n",
    "    ohlc = df.copy()\n",
    "    ohlc = ohlc.set_index(\"Time\").astype(float)  # 确保数值类型正确\n",
    "    # print(ohlc)\n",
    "    return ohlc\n",
    "\n",
    "data = get_data()\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = get_data()\n",
    "# 示例数据：收盘价序列（假设为OHLC数据中的收盘价）\n",
    "# close_prices = pd.Series([...], name='Close', index=pd.date_range(...)) \n",
    "# high_prices = pd.Series([...], name='High')  # 最高价序列 \n",
    "# low_prices = pd.Series([...], name='Low')    # 最低价序列 \n",
    "# volume = pd.Series([...], name='Volume')     # 成交量序列 \n",
    "close_prices = data['Close']\n",
    "high_prices = data['High']\n",
    "low_prices = data['Low']\n",
    "volume = data['Volume']\n",
    "\n",
    "# 计算近期支撑/阻力位（窗口可调）\n",
    "lookback = 11  # 分析窗口 \n",
    "resistance = high_prices.rolling(lookback).max().shift()   # 阻力位（前高）\n",
    "support = low_prices.rolling(lookback).min().shift()       # 支撑位（前低）\n",
    "\n",
    "# 突破判定条件\n",
    "bullish_break = (close_prices > resistance) & (volume > volume.rolling(5).mean())\n",
    "bearish_break = (close_prices < support) & (volume > volume.rolling(5).mean())\n",
    "\n",
    "# 标记ChoCh信号\n",
    "choch_signals = pd.Series(\n",
    "    np.where(bullish_break,  1, np.where(bearish_break,  -1, 0)),\n",
    "    index=close_prices.index,\n",
    "    name='ChoCh'\n",
    ")\n",
    "\n",
    "# 检查突破后的价格确认（例如连续两日收于关键水平之上）\n",
    "confirmed_bullish = bullish_break & (\n",
    "    close_prices.shift(-1) >= resistance.shift(-1))\n",
    "confirmed_bearish = bearish_break & (\n",
    "    close_prices.shift(-1) <= support.shift(-1))\n",
    "\n",
    "# 最终信号过滤\n",
    "final_signals = confirmed_bullish.astype(int) - confirmed_bearish.astype(int)\n",
    "final_signals"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 绘制价格与信号\n",
    "fig, ax = plt.subplots(figsize=(12, 6))\n",
    "close_prices.plot(ax=ax,  label='Price')\n",
    "resistance.plot(ax=ax,  linestyle='--', color='red', label='Resistance')\n",
    "support.plot(ax=ax,  linestyle='--', color='green', label='Support')\n",
    "\n",
    "# 标记ChoCh信号\n",
    "bullish_points = close_prices[final_signals == 1]\n",
    "bearish_points = close_prices[final_signals == -1]\n",
    "ax.scatter(bullish_points.index,  bullish_points, color='red',\n",
    "           marker='^', s=100, label='Bullish ChoCh')\n",
    "ax.scatter(bearish_points.index,  bearish_points, color='green',\n",
    "           marker='v', s=100, label='Bearish ChoCh')\n",
    "\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
